﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Ivony.Fluent;

namespace ExtendLib.Helper
{
    public class HttpHelper
    {
        #region 加载远程html文档返回
        /// <summary>
        /// 模拟Http请求
        /// </summary>
        /// <param name="httpItem">基本请求参数对象</param>
        /// <returns>返回ResponseData对象</returns>
        public static ResponseData GetHtml(HttpRequestItem httpItem)
        {
            #region 设置默认值
            if (httpItem.TimeOut == 0)
            {
                httpItem.TimeOut = 60000;
            }
            if (httpItem.Charset.IsNullOrEmpty())
            {
                httpItem.Charset = "utf-8";
            }
            if (httpItem.Method.IsNullOrEmpty())
            {
                httpItem.Method = "get";
            }
            if (httpItem.ContentType.IsNullOrEmpty())
            {
                httpItem.ContentType = "text/html";
            }
            else if (httpItem.ContentType == "post")
            {
                httpItem.ContentType = "application/x-www-form-urlencoded";
            }
            if (httpItem.UserAgent.IsNullOrEmpty())
            {
                httpItem.UserAgent =
                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0";
            }
            else if (httpItem.UserAgent == "phone")
            {
                httpItem.UserAgent =
                    "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1";
                //httpItem.UserAgent =
                //     "Mozilla/5.0 (iPad; U; CPU OS 3_2_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B500 Safari/531.21.10";
            }
            #endregion
            ResponseData responseData = new ResponseData();
            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(httpItem.Url);
                req.Method = httpItem.Method;
                if (!httpItem.Referer.IsNullOrEmpty())
                {
                    req.Referer = httpItem.Referer;
                }
                else //默认为本页
                {
                    req.Referer = httpItem.Url;
                }
                req.AllowAutoRedirect = httpItem.IsRedirect;
                req.ContentType = httpItem.ContentType;
                req.UserAgent = httpItem.UserAgent;
                req.Timeout = httpItem.TimeOut;
                if (httpItem.ProxyIp.IsNullOrEmpty() == false)
                {
                    req.Proxy = new WebProxy(httpItem.ProxyIp, httpItem.ProxyPort);
                }
                if (httpItem.IsRange)
                {
                    // req.AddRange(0, 1);
                    if (httpItem.RangeSize == 0) //默认没有大小 只请求一小段
                    {
                        req.AddRange(0, 1);
                    }
                    else
                    {
                        req.AddRange(0, httpItem.RangeSize * 1024 * 1024);
                    }
                }
                if (httpItem.HeardCollcetion != null)
                {
                    req.Headers.Add(httpItem.HeardCollcetion);
                }
                if (!httpItem.Cookie.IsNullOrEmpty())
                {
                    req.Headers["Cookie"] = httpItem.Cookie;
                }
                if (httpItem.IsAjax)
                {
                    req.Headers["X-Requested-With"] = "XMLHttpRequest";
                }
                if (httpItem.Method.ToLower() == "post")
                {
                    byte[] bs = null;
                    if (httpItem.Charset == "utf-8")
                    {
                        bs = Encoding.UTF8.GetBytes(httpItem.PostData);
                    }
                    else
                    {
                        bs = Encoding.Default.GetBytes(httpItem.PostData);
                    }
                    req.ContentLength = bs.Length;
                    using (Stream reqStream = req.GetRequestStream())
                    {
                        reqStream.Write(bs, 0, bs.Length);
                        reqStream.Close();
                    }
                }
                if (httpItem.CerPath.IsNullOrEmpty() == false) //带https证书的
                {
                    X509Certificate cert = X509Certificate.CreateFromCertFile(AppDomain.CurrentDomain.BaseDirectory + "\\" + httpItem.CerPath); //证书存放的绝对路径
                    req.ClientCertificates.Add(cert);
                }
                HttpWebResponse response;
                try
                {
                    response = (HttpWebResponse)req.GetResponse();
                }
                catch (WebException ex)
                {
                    LogHelper.WirteLog(string.Format("{0}网址请求异常{1}",httpItem.Url,ex.Message));
                    response = (HttpWebResponse)ex.Response;
                }
                byte[] responseByte = null;
                using (MemoryStream stream = new MemoryStream())
                {
                    #region 处理有gzip的情况
                    //GZIIP处理  
                    if (response.ContentEncoding != null && response.ContentEncoding.Equals("gzip", StringComparison.InvariantCultureIgnoreCase))
                    {
                        //开始读取流并设置编码方式  
                        new GZipStream(response.GetResponseStream(), CompressionMode.Decompress).CopyTo(stream, 10240);
                    }
                    else
                    {
                        //开始读取流并设置编码方式  
                        response.GetResponseStream().CopyTo(stream, 10240);
                    }
                    //获取Byte  
                    responseByte = stream.ToArray();
                    #endregion
                    if (httpItem.IsBackBytes)
                    {
                        responseData.ContentByte = responseByte;
                        return responseData;
                    }
                    #region 最后返回内容
                    responseData.Cookie = response.Headers["Set-Cookie"]; //返回的cookie
                    if (!responseData.Cookie.IsNullOrEmpty())
                    {
                        responseData.Cookie = responseData.Cookie.Replace("Path=/;", "").Replace("Secure;", "").Replace("HttpOnly,", "").Replace("HttpOnly", "").Replace(" ", "").TrimEnd(',', ';');
                    }
                    responseData.Location = response.Headers["location"]; //有的网站是直接返回的跳转地址
                    Encoding end = new UTF8Encoding();
                    if (httpItem.Charset != "utf-8")
                    {
                        end = Encoding.Default;
                    }
                    responseData.DataInfo = end.GetString(responseByte); //返回内容 
                    #endregion
                }
            }
            catch (Exception e)
            {
                LogHelper.WirteLog(string.Format("{0}网址请求异常{1}", httpItem.Url, e.Message));
            }
            return responseData;
        }
        #endregion
    }

    /// <summary>
    /// Http请求参数实体类
    /// </summary>
    public class HttpRequestItem
    {
        /// <summary>
        /// 请求URl
        /// </summary>
        public string Url { get; set; }
        /// <summary>
        /// 编码方式 utf-8 或gb2312
        /// </summary>
        public string Charset { get; set; }
        /// <summary>
        /// 请求Cookie
        /// </summary>
        public string Cookie { get; set; }
        /// <summary>
        /// 请求方式 get|post
        /// </summary>
        public string Method { get; set; }
        /// <summary>
        /// 请求超时时间
        /// </summary>
        public int TimeOut { get; set; }
        /// <summary>
        /// 防盗链地址 即上一页地址
        /// </summary>
        public string Referer { get; set; }
        /// <summary>
        /// 内容形式 text/html |application/x-www-form-urlencoded
        /// </summary>
        public string ContentType { get; set; }
        /// <summary>
        /// Post数据
        /// </summary>
        public string PostData { get; set; }
        /// <summary>
        /// 获取网站种子转磁力
        /// </summary>
        public bool IsDownZongZi { get; set; }
        /// <summary>
        /// 是否返回二进制流 用户视频过度 有的mp4地址直接访问不行 必需要一些cookie或者其它参数才行
        /// </summary>
        public bool IsBackBytes { get; set; }
        /// <summary>
        /// 是否需要ajax校验  true 请求头加上X-Requested-With:XMLHttpRequest
        /// </summary>
        public bool IsAjax { get; set; }
        /// <summary>
        /// 浏览器标识 默认为电脑版本浏览器
        /// </summary>
        public string UserAgent { get; set; }
        /// <summary>
        /// 是否显示Range 有的网站需要这个 11月08日 添加
        /// </summary>
        public bool IsRange { get; set; }
        /// <summary>
        /// 当IsRange为True时 设置请求长度 MB单位
        /// </summary>
        public int RangeSize { get; set; }
        /// <summary>
        /// 是否自动从定向 默认否
        /// </summary>
        public bool IsRedirect { get; set; }
        /// <summary>
        /// 证书(虚拟路径即可 http转换了)
        /// </summary>
        public string CerPath { get; set; }
        /// <summary>
        /// 请求头部
        /// </summary>
        public NameValueCollection HeardCollcetion { get; set; }
        /// <summary>
        /// 代理Ip
        /// </summary>
        public string ProxyIp { get; set; }
        /// <summary>
        /// 代理端口
        /// </summary>
        public int ProxyPort { get; set; }
    }

    /// <summary>
    /// http请求返回的对象
    /// </summary>
    public class ResponseData
    {
        /// <summary>
        /// http请求返回的Cookie
        /// </summary>
        public string Cookie { get; set; }
        /// <summary>
        /// http请求返回的文本
        /// </summary>
        public string DataInfo { get; set; }
        /// <summary>
        /// http请求返回的地址
        /// </summary>
        public string Location { get; set; }
        /// <summary>
        /// 内容长度 （单位：MB） 检查视频地址是否有效
        /// </summary>
        public double ContentLength { get; set; }
        /// <summary>
        /// 内容二进制流 一般用于视频网站跳转过度
        /// </summary>
        public byte[] ContentByte { get; set; }
    }
}